package GUI;

import java.util.*;

import Control.CatchEpisode;
import Control.CatchPhrase;
import Control.CatchSeason;
import Control.Character;
import Control.CharacterCatchEpisode;
import Control.CharacterCatchSeason;
import Control.CharacterContainer;
import Control.CharacterDialogEpisode;
import Control.DialogEpisode;
import Control.Episode;
import Control.Season;



import processing.core.PApplet;
import processing.core.PFont;


public class Utils {
	//TODO Put general use variables here 
	public static ArrayList<Character> characters;
	public static ArrayList<Season> seasons;
	public static ArrayList<Episode> episodes;
	public static ArrayList<CatchPhrase> catchphrases;
	public static ArrayList<Episode> firstOfSeason;




	//GUI
	static int width=1024;
	static int height=768;
	static int graphAreaCenterX = 387;
	static int graphAreaCenterY = 479;
	static int graphAreaWidth = 773;
	static int graphAreaHeight =576;
	static int graphAreaLowerLeftX = 50;
	static int graphAreaLowerLeftY = 690;
	static int graphAreaUpperRightX = 742; //772
	static int graphAreaUpperRightY =323;
	static int MAX_CATCHPHRASE_LENGTH=22;
	static int MAX_EPISODE_LENGTH=23;
	static int BAR_ICON_WIDTH = 110;
	static int BAR_ICON_HEIGHT = 110;
	public static Main globalProcessing;
	static PFont plotFont;
	static PFont plotBoldFont;
	static GradientUtils gu;
	static int backGroundColor = 35;
	static int textColor = 255;
	static ArrayList<Character> characterSelected;
	static ArrayList<CatchPhrase> catchPhrasesSelected;
	static Episode startEpisodeSelected;
	static Episode endEpisodeSelected;
	static TextBox characterTextBox;
	static TextBox catchPhrasesTextBox;
	static ArrayList<CharacterButton> characterSuggestionButtons;
	static ArrayList<CatchPhraseButton> catchPhraseSuggestionButtons;
	static CharacterCatchInfoPanel ccip;
	static boolean affineCharactersActive;
	static AffineCharactersButton tagCloudACB;
	static boolean tagCloudActive;
	static CommonWordsButton tagCloudCWB;
	static ArrayList<IconButton> iconBarButtons;
	//static String[] names= {"Beate", "Claudia", "Fjodor", "Fred", "Friedrich",	"Fritz", "Frodo", "Hermann", "Willi"};
	public static SeasonEpisodeInfoPanel seip;
	public static ScrollBarHorizontal hs;
	public static GraphArea graphArea;
	public static int scaleEpisode = 114;
	public static int tableBackgroundColor=35; //200
	public static int tableTextColor = 255; //0 
	public static int tableLineColor = 60; //0
	public static int[] colors;
	public static int[] strokeWeight;
	public static String xAxisString="Characters";
	public static String yAxisString0="";
	public static String yAxisString1="Lines";
	public static String yAxisString2="Spoken";
	static boolean showCatchPhrases;
	public static EpisodeButton episodeHighLight;
	public static CharacterInfoPanelButton characterInfoPanelHighLight;
	public static CatchPhraseInfoPanelButton catchPhraseInfoPanelHighLight;
	public static InfoButton infoButton;


	//Methods for obtaining data to plot 

	//return list of characters with data to be displayed -- dialogs, appearances, episode granularity
	static ArrayList<CharacterContainer> returnXEpisode(ArrayList<Character> characters){ 
		int startIndex = Episode.returnIndex(Utils.episodes, Utils.startEpisodeSelected);
		int stopIndex = Episode.returnIndex(Utils.episodes, Utils.endEpisodeSelected) + 1;
		ArrayList<CharacterContainer> results = new ArrayList<CharacterContainer>();


		if(startIndex == -1 || stopIndex == 0 || startIndex >= stopIndex) //start and stop indexes must be consistent
			return null;

		if(characters.size()==0) //There must be at least 1 character selected
			return null;

		for(int i = 0; i < characters.size(); i++){
			Character character = characters.get(i);
			CharacterDialogEpisode cde = new CharacterDialogEpisode(character);
			for(int j = startIndex; j < stopIndex; j++){
				Episode ep = Utils.episodes.get(j);
				int appearance = 0;
				int numLines = 0;
				if(ep.getNumLines().containsKey(character)){
					appearance++;
					numLines += ep.getNumLines().get(character);
				}
				DialogEpisode de = new DialogEpisode(ep, appearance,numLines);
				cde.add(de);
			}
			if(!results.contains(cde))
				results.add(cde);

		}
		return results;
	}

	//return list of characters with data to be displayed -- dialogs, appearances, season granularity
	static ArrayList<CharacterContainer> returnXSeason(ArrayList<Character> characters){ 
		int seasonStart = Utils.startEpisodeSelected.getSeason().getNumber();
		int seasonEnd = Utils.endEpisodeSelected.getSeason().getNumber();
		int startIndex = Episode.returnIndex(Utils.episodes, Utils.firstOfSeason.get(seasonStart-1));
		int stopIndex;
		if(seasonEnd == Utils.firstOfSeason.size())
			stopIndex = Utils.episodes.size()-1;
		else
			stopIndex = (Episode.returnIndex(Utils.episodes, Utils.firstOfSeason.get(seasonEnd)))-1;
		ArrayList<CharacterContainer> results = new ArrayList<CharacterContainer>();


		if(startIndex == -1 || stopIndex == 0 || startIndex >= stopIndex) //start and stop indexes must be consistent
			return null;

		if(characters.size()==0) //There must be at least 1 character selected
			return null;

		for(int i = 0; i < characters.size(); i++){
			Character character = characters.get(i);
			CharacterDialogEpisode cde = new CharacterDialogEpisode(character);
			int appearance = 0;
			int numLines = 0;
			for(int j = startIndex; j < stopIndex; j++){
				Episode ep = Utils.episodes.get(j);
				if(ep.getNumLines().containsKey(character)){
					appearance++;
					numLines += ep.getNumLines().get(character);
				}
				if(j == stopIndex-1 || !ep.getSeason().equals(Utils.episodes.get(j+1).getSeason())){
					DialogEpisode de = new DialogEpisode(ep, appearance,numLines);
					cde.add(de);
					appearance = 0;
					numLines = 0;
				}
			}
			if(!results.contains(cde))
				results.add(cde);

		}
		return results;
	}


	//this function needs for each catchphrase selected, the corresponding character present in Utils.characterSelected
	static ArrayList<CharacterContainer> returnXEpisodeCatch(ArrayList<Character> characters){ 
		int startIndex = Episode.returnIndex(Utils.episodes, Utils.startEpisodeSelected);
		int stopIndex = Episode.returnIndex(Utils.episodes, Utils.endEpisodeSelected) + 1;
		boolean found;
		ArrayList<CharacterContainer> results = new ArrayList<CharacterContainer>();


		if(startIndex == -1 || stopIndex == 0 || startIndex > stopIndex) //start and stop indexes must be consistent
			return null;

		if(Utils.catchPhrasesSelected.size() == 0) //There must be at least 1 catch phrase selected
			return null;

		if(characters.size() == 0) //There must be at least 1 character selected
			return null;

		for(int i = 0; i < characters.size(); i++){
			Character character = characters.get(i);
			found = false;
			CatchPhrase cp = new CatchPhrase();
			CharacterCatchEpisode cce = new CharacterCatchEpisode(character);
			for(int j = 0; j < character.getCatchphrases().size(); j++){
				if(!Utils.catchPhrasesSelected.contains(character.getCatchphrases().get(j)))
					continue;
				cp = character.getCatchphrases().get(j);
				found = true;
				for(int k = startIndex; k < stopIndex; k++){
					Episode ep = Utils.episodes.get(k);
					int count = 0;
					if(ep.getNumCatchphrases().containsKey(cp)){
						count += ep.getNumCatchphrases().get(cp);
					}
					CatchEpisode ce = new CatchEpisode(ep, cp,  count);
					cce.add(ce);
				}

			}
			if(found)
				results.add(cce);
		}
		return results;

	}



	//this function needs for each catchphrase selected, the corresponding character present in Utils.characterSelected
	static ArrayList<CharacterContainer> returnXSeasonCatch(ArrayList<Character> characters){
		int seasonStart = Utils.startEpisodeSelected.getSeason().getNumber();
		int seasonEnd = Utils.endEpisodeSelected.getSeason().getNumber();
		int startIndex = Episode.returnIndex(Utils.episodes, Utils.firstOfSeason.get(seasonStart-1));
		int stopIndex;
		if(seasonEnd == Utils.firstOfSeason.size())
			stopIndex = Utils.episodes.size()-1;
		else
			stopIndex = (Episode.returnIndex(Utils.episodes, Utils.firstOfSeason.get(seasonEnd)))-1;
		boolean found;
		ArrayList<CharacterContainer> results = new ArrayList<CharacterContainer>();


		if(startIndex == -1 || stopIndex == -1 || startIndex > stopIndex) //start and stop indexes must be consistent
			return null;

		if(Utils.catchPhrasesSelected.size() == 0) //There must be at least 1 catch phrase selected
			return null;

		if(characters.size() == 0) //There must be at least 1 character selected
			return null;

		for(int i = 0; i < characters.size(); i++){
			Character character = characters.get(i);
			found = false;
			CatchPhrase cp = new CatchPhrase();
			CharacterCatchSeason ccs = new CharacterCatchSeason(character);
			for(int j = 0; j < character.getCatchphrases().size(); j++){
				if(!Utils.catchPhrasesSelected.contains(character.getCatchphrases().get(j)))
					continue;
				cp = character.getCatchphrases().get(j);
				found = true;
				int count = 0;
				for(int k = startIndex; k < stopIndex; k++){
					Episode ep = Utils.episodes.get(k);
					if(ep.getNumCatchphrases().containsKey(cp)){
						count += ep.getNumCatchphrases().get(cp);
					}
					if(k == stopIndex -1 || !ep.getSeason().equals(Utils.episodes.get(k+1).getSeason())){
						CatchSeason cs = new CatchSeason(ep.getSeason(), cp, count);
						ccs.add(cs);
						count = 0;
					}
				}

			}
			if(found)
				results.add(ccs);
		}
		return results;
	}

	public static ArrayList<Character> getCharactersAppeared(Episode start,
			Episode end) {
		ArrayList<Character> results = new ArrayList<Character>();
		if(start == null || end == null || absoluteIndex(start) < 0 || 
				absoluteIndex(end) < 0 || absoluteIndex(end) < absoluteIndex(start)){
			System.out.println("Start = " + start.toString() + " End = " + end.toString());
			return null;
		}
		if(Utils.graphArea!=null){
			if(!Utils.graphArea.seasonEpisodeButton.state){
				start = Utils.firstOfSeason.get(start.getSeason().getNumber()-1);
				if(end.getSeason().getNumber() == Utils.firstOfSeason.size())
					end = Utils.episodes.get(Utils.episodes.size()-1);
				else 
					end = Utils.episodes.get(Utils.absoluteIndex(Utils.firstOfSeason.get(end.getSeason().getNumber()))-1);
			}
		}
		else{
			start = Utils.firstOfSeason.get(start.getSeason().getNumber()-1);
			if(start.getSeason().getNumber() == Utils.firstOfSeason.size())
				end = Utils.episodes.get(Utils.episodes.size()-1);
			else 
				end = Utils.episodes.get(Utils.absoluteIndex(Utils.firstOfSeason.get(start.getSeason().getNumber()))-1);
		}
		for(int i = Utils.episodes.indexOf(start); i <= Utils.episodes.indexOf(end); i++){
			Episode ep = Utils.episodes.get(i);
			Object list[] = ep.getNumLines().keySet().toArray();
			for(int j = 0; j < list.length; j++){
				Character c = (Character)list[j];
				//System.out.println(c.toString());
				if(!results.contains(c))
					results.add(c);
			}
		}
		return results;



	}

	public static int absoluteIndex(Episode ep){
		return Utils.episodes.indexOf(ep);
	}

	public static int maxValue(List<CharacterContainer> list){

		int max = 0;

		for(int i = 0; i < list.size(); i++)
			for(int j = 0; j < list.get(i).getList().size(); j++)
				if(list.get(i).getList().get(j).value() > max)
					max = list.get(i).getList().get(j).value();
		return max;
	}


}
